#include "processPool.hpp"

class cgi_con
{
public:
    cgi_con()
    {}

    ~cgi_con()
    {}

    void init(int epfd, int sockfd, const struct sockaddr_in& client)
    {
        m_epfd = epfd;
        m_sockfd = sockfd;
        m_read_idx = 0;
        m_client_address = client;
        memset(m_buf, '\0', BUFFER_SIZE);
    }

    void process()
    {
        int idx = 0;
        while (true)
        {
            idx = m_read_idx;
            int ret = recv(m_sockfd, m_buf + idx, BUFFER_SIZE - 1 - idx, 0);
            if (ret > 0)
            {
                m_read_idx += ret;
                for (;idx < m_read_idx;idx++)
                {
                    if (idx >= 1 && m_buf[idx-1] == '\r' && m_buf[idx] == '\n')
                        break;
                }
                //数据还没有读完，继续读数据
                if (idx == m_read_idx)
                    continue;
                m_buf[idx-1] = '\0';
                printf("client# %s\n", m_buf);

                //判断客户要执行CGI程序是否存在
                char* file_name = m_buf;
                if (access(file_name, F_OK) == -1)
                {
                    util::removeEvent(m_epfd, m_sockfd);
                    break;
                }

                //创建子进程来执行CGI程序
                pid_t id = fork();
                if (id < 0)
                {
                    printf("fork failed\n");
                    util::removeEvent(m_epfd, m_sockfd);
                    break;
                }
                else if (id > 0)
                {
                    util::removeEvent(m_epfd, m_sockfd);
                    break;
                }
                else
                {
                    printf("child process\n");
                    close(STDOUT_FILENO);
                    dup(m_sockfd);
                    printf("%s\n", m_buf);
                    execl(m_buf, m_buf, NULL);
                    exit(0);
                }
            }
            else if (ret == 0)
            {
                util::removeEvent(m_epfd, m_sockfd);
                break;
            }
            else
            {
                if (errno != EAGAIN)
                {
                    util::removeEvent(m_epfd, m_sockfd);
                }
                break;
            }
        }
    }
private:
    int m_sockfd;
    static int m_epfd;
    struct sockaddr_in m_client_address;
    static const int BUFFER_SIZE = 1024;
    char m_buf[BUFFER_SIZE];
    int m_read_idx;
};

int cgi_con::m_epfd = -1;

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        printf("Usage: %s port\n", argv[0]);
        return 1;
    }
    int port = atoi(argv[1]);
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(port);

    int listen_sock = socket(PF_INET, SOCK_STREAM, 0);
    assert(listen_sock != -1);
    int op = 1;
    int ret = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEPORT, &op, sizeof(op));
    assert(ret != -1);
    bind(listen_sock, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);
    ret = listen(listen_sock, 5);
    assert(ret != -1);

    //获取线程池对象
    processPool<cgi_con>* ppl = processPool<cgi_con>::create(listen_sock);
    assert(ppl);
    ppl->run();

    //释放资源
    delete ppl;
    close(listen_sock);
    return 0;
}